Introducción a R

Resumen

En el presente documento se da una breve introducción al lenguaje R. Exploraremos desde las funciones más básicas del lenguaje (como leer tablas de datos, hacer aritmética, algunas operaciones algebraicas) hasta cómo utilizar funciones de paquetes especializados para el análisis espacial (i.e. raster, rgdal, dismo). También se hará énfansis en cómo programar funciones propias o funciones definidas por el usuario (helper functions) las cuales tienen el objetivo de facilitarnos tareas complejas. Es importante notar que operaciones básicas como la indexación suelen ser vitales para poder realizar operaciones mucho más complicadas y complejas dentro de los loops y estructuras de control.

Qué es, de dónde y cómo instalo R?

R es un lenguaje de programación de código abierto el cual está basado en el lenguaje S. En sus inicios el lenguaje realizaba solo operaciones estadísticas y gráficas, sin embargo a través de los años se ha convertido en un lenguaje polifacético en donde podemos encontrar desde paquetes para el análisis de textos (text mining), web scraping, análisis espaciales (i.e. spatstat) hasta para la programación de aplicaciones web (i.e shiny). Lo anterior se debe a que varios de sus usuarios se han convertido en desarrolladores activos de la comunidad. Acutualmente existen casi 13000 paquetes (Fig. 1), el crecimiento de estos ha sido exponencial (Fig. 2).

Figura_1

Figura 1. Número de paquetes en CRAN

Figura 2. Serie de tiempo del número de paquetes en CRAN

Obtención e instalación de R

R se puede descargar de la siguiente página web http://www.r-project.org/. Figura_3

En el panel izquierdo encontrarás la opción de download donde elegirás un mirror para descargarlo, los links para México son los siguientes:

Elige el link de descarga que te parezca más adecuado en función del área en que te encuentres. Una vez elegido el mirror, selecciona la versión de R de acuerdo a tu sistema operativo (Linux, Mac o Windows).

Figura_4

Figura_4

La forma más fácil de instalar R es por medio de los binarios (o ejecutables), sin embargo si deseas instalarlo desde terminal de Linux o Mac aquí puedes encontrar las instrucciones:

Antes de empezar con el tutorial voy a fijar una semilla aleatoria para que los ejemplos de este documento sean reproducibles (es decir, para que todos en el grupo lleguen a los mismos resultados).

También fijen como directorio de trabajo la carpeta que descargaron de mi repositorio de github (CursoNichos2019)

Tutorial: Introducción a R

Una vez que han instalado R en sus computadoras ahora estamos listos para comenzar a aprender programación en este ambiente maravilloso.

Sintaxis

La primera cosa que hay que explorar es la sintaxis del lenguaje; en esta sección daremos un panorama general de ella. La primera cosa que hay que tener en cuenta sobre la sintaxis de R es que a diferencia de otros lenguajes como SQL, BASIC, Pascal, R es sensible a mayúsculas y minúsculas por lo que un objeto llamado libro es diferente a Libro. Veamos el ejemplo:

## [1] TRUE
## [1] FALSE

A pesar de que no se comentó anteriormente (se dio por hecho), en R la forma de declarar variables es mediante el comando de asignación (<-). Aunque también es posible declarar las variables con el signo (=) se recomienda usar <-. Veremos más sobre variables en las siguientes secciones

## [1] 1
## [1] 2
## [1] 3

Otra característica de la sintaxis es que en R solo se permite nombrar a las variables comenzando con letras (mayúsculas o minúsculas) o “.”* y nunca con números.

## [1] "Dulce"
## [1] "Agradable"

Las variables pueden contener números en cualquier otra posición (nunca al comienzo).

## [1] "fresco"
## [1] "fresco"

Ahora probemos con el “.”*

## [1] "SOS"

R como calculadora

La consola de R puede ser usada como calculadora aritmética, vemos algunas operaciones básicas:

Una suma

## [1] 94

Una resta

## [1] -149

Una multiplicación

## [1] 196

División

## [1] 1.2

Potencia

## [1] 387420489

El residuo de la división

## [1] 2

La parte entera

## [1] 1

Podemos verificar que 9 es la suma de su residuo más 7 veces la parte entera de la fracción

## [1] 9

Los paréntesis puede ser usados para especificar el orden de las operaciones

## [1] 2.713765

La operación aterior es una forma de estimar el número \(e\)

\[\lim _{n\to \infty }\left(1+{\frac {1}{n}}\right)^{n}=e.\]

R contiene algunas funciones matemáticas ya incluidas como \(\sin(x)\), \(\cos(x)\), \(\tan(x)\), (en radianes), \(\exp(x)\), \(\log(x)\) y \(\sqrt{x}\).

## [1] 2.718282
## [1] 0.841471
## [1] 0.5403023
## [1] 0
## [1] 1

También tiene en memoria algunas constantes como \(\pi\)

## [1] 3.141593

Podemos especificar la precisión de las salidas con el comando options

## [1] 3.141592653589793

Redondear cantidades

## [1] 2.94
## [1] 1
## [1] 0

Variables (Global environment)

R tiene un ambiente de trabajo conocido como ambiente global (Global environment) en donde se guardan los resultados de los cálculos. Los resultados se guardan en forma de objetos o variables; una variable es como un folder etiquetado donde guardamos documentos, éstos puede ser de diversa naturaleza y siempre tenemos la opción de cambiar el contenido de ellos, sin embargo, el folder se llamará de la misma manera.

Las variables globales se encuentran en el Global environment y pueden ser llamadas en cualquier momento durante la sesión; así, si quisiéramos almacenar una cantidad, digamos la tasa de interés anual a la que pagaremos un coche, podemos guardarla en la variable i.e. tasa_anual y utilizarla cuando la necesitemos.

Imaginemos que vamos a comprar un Audi RS5 4.2 FSI 450 hp y que queremos pagarlo a 48 meses (4 años). La tasa anual que maneja audi es aproximadamente de 12.9%; olvidándonos de los pagos de comisión por apertura etc. hagamos el cálculo de cuánto pagaremos por nuestro Audi (Fig. 5).

figura_5

Figura 5. Audi RS5 4.2 FSI 450 hp

## [1] 191552.1
## [1] 766208.4
## [1] 2251108.4

Los vectores y matrices en R

Comencemos con algunas definiciones necesarias:

  • Escalar: Un escalar es sólo una cantidad numérica i.e. un entero o un número real.
  • Vector \(v \in \mathbb{R}^n\) : Se llama vector de dimensión \(n\) a una tupla de \(n\) números reales o componentes del vector (un vector está constituido por 1 o varios escalares).

El conjunto de todos los vectores de dimensión \(n\), se representa como \(\mathbb{R}^n\). Así, un vector \({\textbf v}\) perteneciente a un espacio \(\mathbb{R}^n\) se representa como:

\({\textbf v} = (a_1, a_2, a_3, \dots, a_n)\) donde \({\textbf v} \in \mathbb{R}^n\)

En matemáticas existen dos tipos de vectores, el vector renglón (el de la ecuación de arriba) y el vector columna.

Vector columna

\[\textbf v= \left( \begin{array}{c} a_1\\ a_2\\ \vdots\\ a_n\\ \end{array} \right)\]

Para saber más sobre las operaciones matemáticas de vectores y matrices en R da clic aquí.

Indexación de vectores en R

Nótese que se puede localizar a cada componente del vector por su posición (ver ejemplo).

\[\textbf f = (5,2,4,3)\]

De modo que la componente 3 del vector \(\textbf f\) es el número \(4\). En R, a lo anterior se le denomina indexación y es una de las herramientas más poderosas que podemos aprender; si logramos dominar este arte, la programación y automatización de tareas muy complejas será mucho más sencilla.

El desconocimiento de la forma en cómo se indexan los vectores o matrices hace que el código fuente de los programas o scripts sea obscuro. En los siguientes ejemplos veremos que esta arte es mucho más clara de lo que parece.

Primero debemos notar que en R la forma más básica de construir vectores es utilizando la función concatenar “c”. Este comando concatena a cada uno de los elementos que formarán a nuestro vector.

Comprobemos si efectivamente el elemento 3 del vector \({\textbf f}\) es el número \(4\)

## [1] 4

Efectivamente es el número 4 y que hay del primer elemento?

## [1] 5

Si quisiéramos extraer más de un elemento (un subconjunto \(\textbf f_1\) de dimensión \(m\) con \(m \le n\)) del vector \({\textbf f}\)?

Ahora se muestra como formar un subconjunto \(\textbf f_1\) constituido por los elementos 1, 3 y 4 del vector \({\textbf f}\)

## [1] 5 4 3

Nota: En algunos lenguajes como python la indexación comienza con el 0.

Generación de secuencias (vectores) regulares en R

R tiene varias formas de generar secuencias, por ejemplo, el comando 1:n genera la secuencia \(1,2,3,\dots,n\). La secuencia anterior es una de las más utilizadas para generar subconjuntos de vectores de dimensión \(n\) y cuyos elementos son números enteros.

##  [1]  1  2  3  4  5  6  7  8  9 10

Otro comando que encontraremos con frecuencia es el comando “seq”, este comando genera secuencias de números en el intervalo \([a,b]\) con particiones de tamaño \(\delta\).

Generemos una secuencia de números del 0 al 10 de 2 en 2, es decir \(\delta=2\)

## [1]  0  2  4  6  8 10

Ahora una secuencia de 0 a 1 con \(\delta=0.01\)

##   [1] 0.00000000000000000 0.01000000000000000 0.02000000000000000
##   [4] 0.03000000000000000 0.04000000000000000 0.05000000000000000
##   [7] 0.06000000000000000 0.07000000000000001 0.08000000000000000
##  [10] 0.09000000000000000 0.10000000000000001 0.11000000000000000
##  [13] 0.12000000000000000 0.13000000000000000 0.14000000000000001
##  [16] 0.14999999999999999 0.16000000000000000 0.17000000000000001
##  [19] 0.17999999999999999 0.19000000000000000 0.20000000000000001
##  [22] 0.20999999999999999 0.22000000000000000 0.23000000000000001
##  [25] 0.23999999999999999 0.25000000000000000 0.26000000000000001
##  [28] 0.27000000000000002 0.28000000000000003 0.28999999999999998
##  [31] 0.29999999999999999 0.31000000000000000 0.32000000000000001
##  [34] 0.33000000000000002 0.34000000000000002 0.35000000000000003
##  [37] 0.35999999999999999 0.37000000000000000 0.38000000000000000
##  [40] 0.39000000000000001 0.40000000000000002 0.41000000000000003
##  [43] 0.41999999999999998 0.42999999999999999 0.44000000000000000
##  [46] 0.45000000000000001 0.46000000000000002 0.47000000000000003
##  [49] 0.47999999999999998 0.48999999999999999 0.50000000000000000
##  [52] 0.51000000000000001 0.52000000000000002 0.53000000000000003
##  [55] 0.54000000000000004 0.55000000000000004 0.56000000000000005
##  [58] 0.57000000000000006 0.57999999999999996 0.58999999999999997
##  [61] 0.59999999999999998 0.60999999999999999 0.62000000000000000
##  [64] 0.63000000000000000 0.64000000000000001 0.65000000000000002
##  [67] 0.66000000000000003 0.67000000000000004 0.68000000000000005
##  [70] 0.69000000000000006 0.70000000000000007 0.70999999999999996
##  [73] 0.71999999999999997 0.72999999999999998 0.73999999999999999
##  [76] 0.75000000000000000 0.76000000000000001 0.77000000000000002
##  [79] 0.78000000000000003 0.79000000000000004 0.80000000000000004
##  [82] 0.81000000000000005 0.82000000000000006 0.83000000000000007
##  [85] 0.83999999999999997 0.84999999999999998 0.85999999999999999
##  [88] 0.87000000000000000 0.88000000000000000 0.89000000000000001
##  [91] 0.90000000000000002 0.91000000000000003 0.92000000000000004
##  [94] 0.93000000000000005 0.94000000000000006 0.95000000000000007
##  [97] 0.95999999999999996 0.96999999999999997 0.97999999999999998
## [100] 0.98999999999999999 1.00000000000000000

Imaginemos que se quiere una secuencia de números definidos en el intervalo \((13,25)\) pero cuya longitud sea de 40 números. Uno de los argumentos del comando seq es length.out y con este se puede especificar la longitud de la secuencia de valores que queremos generar.

##  [1] 13.00000000000000 13.30769230769231 13.61538461538461
##  [4] 13.92307692307692 14.23076923076923 14.53846153846154
##  [7] 14.84615384615385 15.15384615384615 15.46153846153846
## [10] 15.76923076923077 16.07692307692308 16.38461538461539
## [13] 16.69230769230769 17.00000000000000 17.30769230769231
## [16] 17.61538461538462 17.92307692307692 18.23076923076923
## [19] 18.53846153846154 18.84615384615385 19.15384615384615
## [22] 19.46153846153846 19.76923076923077 20.07692307692308
## [25] 20.38461538461539 20.69230769230769 21.00000000000000
## [28] 21.30769230769231 21.61538461538462 21.92307692307692
## [31] 22.23076923076923 22.53846153846154 22.84615384615385
## [34] 23.15384615384615 23.46153846153846 23.76923076923077
## [37] 24.07692307692308 24.38461538461539 24.69230769230769
## [40] 25.00000000000000

El comando rep

La función rep permite generar secuencias repetidas de vectores.

## [1] "A" "B" "A" "B"
## [1] "A" "A" "B" "B"

El comando sample

Un comando frecuentemente utilizado para extraer una muestra aleatoria de un vector el comando sample. Algunos de sus argumentos son:

  • El vector de donde se va a sacar la secuencia aleatoria (\(x\)).
  • El número de elementos (size) que se van a extraer del vector \(x\).
  • La muestra será obtenida con remplazo (replace)

En el siguiente ejemplo crearemos un vector de 1000 elementos y tomaremos una muestra aleatoria de 100. Veamos cómo hacerlo en R!

##   [1] 377 922 990 975 236 107  39 723 130 397 234 344 895 625 665 956 552
##  [18] 546 730 364 169 681 139  80 420 977 945 487 297 884 898 687 848 307
##  [35] 424  69 384 709 656  35 575 882 948 896 607 382  65 140 266 806 952
##  [52] 964 125 839 652 840 842 645 658 692 988 501 526 450 851 477 425 861
##  [69] 573 103 268 733 774 935 784 200 819 373 517 445 756  26 449 282 358
##  [86] 563 472  83 902 267 528 554 757 543  70 836 828 289 808 456

Midiendo la longitud de un vector

Cómo saber la longitud del vector \(\textbf l\) en R es muy sencillo, el comando para realizarlo es length

## [1] 401

Las matrices en R

  • Matriz: Es un arreglo bidimensional de números donde cada elemento de la matriz \(\textbf M\) se puede identificar por la fila \(i\) y la columna \(j\) a la que pertenece.

En R las matrices pueden ser de 2 tipos:

  1. Numérica
  2. Cadena

Lo anterior quiere decir que no podemos combinar números con caracteres. Si fuera este el caso, R internamente realiza una operación conocida como casteo cast y convierte a todos los elementos a caracteres (strings)

Creación de matrices en R

Las matrices en R se crean con el comando matrix y sólo necesitamos indicar los elementos que la conformarán (data), el número de filas (nrow) y columnas (ncol) que contendrá.

##      [,1] [,2] [,3] [,4]
## [1,]    1    5    9   13
## [2,]    2    6   10   14
## [3,]    3    7   11   15
## [4,]    4    8   12   16

Acomodar los elementos de la matriz por renglón

##      [,1] [,2] [,3] [,4]
## [1,]    1    2    3    4
## [2,]    5    6    7    8
## [3,]    9   10   11   12
## [4,]   13   14   15   16

Como se había mencionado las matrices en R sólo pueden ser de dos tipos numéricas o de cadena de caracteres:

##      [,1] [,2] [,3]
## [1,] "A"  "D"  "G" 
## [2,] "B"  "E"  "H" 
## [3,] "C"  "F"  "I"

Tratemos de combinar números con letras

##      [,1] [,2] [,3] [,4]
## [1,] "A"  "E"  "1"  "5" 
## [2,] "B"  "F"  "2"  "6" 
## [3,] "C"  "G"  "3"  "7" 
## [4,] "D"  "H"  "4"  "8"

Indexación de matrices en R

Sea \(\textbf M\) una matriz de \(6\times 8\) dimensiones. Supongamos que se nos pide extraer el elemento que corresponde a la fila 3 y al renglón 6. La forma de indexar matrices en R sigue la misma lógica que en matemáticas en donde \(\mathbf{M_{fila,columna}}\) en R se indexa como \(\mathbf{M[fila,columna]}\). Veamos el código!

## [1] 2.893617021276595

También podemos usar la indexación para mostrar una sola fila de la matriz, una columna completa, los primeros \(m\) elementos de una fila o una columna, las primeras \(k\) columnas y las primeras \(r\) filas de la matriz…

Llamando sólo una fila de una matriz

A continuación se muestra como enlistar la segunda fila de la matriz \(\mathbf M\)

## [1] 2.340425531914894 2.382978723404255 2.425531914893617 2.468085106382979
## [5] 2.510638297872340 2.553191489361702 2.595744680851064 2.638297872340425

Llamando sólo una columna de una matriz

A continuación se muestra como enlistar la tercera columna de la matriz \(\mathbf M\)

## [1] 2.085106382978724 2.425531914893617 2.765957446808510 3.106382978723405
## [5] 3.446808510638298 3.787234042553191

Combinando formas de indexar

Con las operaciones vistas hasta el momento podemos realizar varias combinaciones para extraer elementos de una matriz. Veamos algunos ejemplos de lo anterior.

Dada la matriz \(\mathbf {M_{5,5}}\) extraer:

  1. las primeras 3 filas de las columnas 1 y 2
##      [,1] [,2]
## [1,]    1    2
## [2,]    6    7
## [3,]   11   12
  1. Las filas de 1 a la 5 de las columas 1 y 5
##      [,1] [,2]
## [1,]    1    5
## [2,]    6   10
## [3,]   11   15
## [4,]   16   20
## [5,]   21   25

Para saber más sobre matrices y sus operaciones en R da clic aquí.

Los data.frame

Al igual que las matrices, un data.frame es un arreglo bidimensional de reglones y columnas. A diferencia de las matrices este permite tener columnas de tipo numérico y de tipo caracter en él. Cada columna representa una variable (en el sentido estadístico).

Construcción de data.frames

La función data.frame permite contruir un data.frame a partir de vectores; cada vector representa una variable o columna en el data.frame. A continuación veremos cómo construir un data.frame cuyas variables son de tipo numérico y de tipo caracter.

Pollitos

Construiremos una tabla de datos (data.frame) que tenga información sobre 5 lotes de 15 pollitos a los cuales daremos un identificador a nivel individuo y a nivel lote y también llevaremos un registro de su peso. El peso inicial promedio de los pollitos es de \(10 \pm 2\) gramos

pollito_id lote peso_inicial
1 1 L1 10.117280656471848
2 2 L1 8.403909455984831
3 3 L1 10.536609089933336
21 21 L2 9.371508447453380
22 22 L2 10.867016064003110
23 23 L2 9.151747692376375
31 31 L3 10.733573765493929
32 32 L3 10.086726178415120
33 33 L3 9.055966132320464
51 51 L4 8.916218001395464
52 52 L4 11.705493338406086
53 53 L4 8.345597507432103
71 71 L5 11.453125244937837
72 72 L5 10.272650724276900
73 73 L5 9.875873841345310

Agregando datos al data.frame

Supóngase que a cada lote de pollitos se les alimenta con una dieta diferente durante 45 días, por lo tanto será necesario agregar la variable dieta a nuestra tabla de datos.

También la variable peso después de los 45 días de engorde.

pollito_id lote peso_inicial Dieta peso_dieta
1 1 L1 10.117280656471848 D1 2250.309358306802
2 2 L1 8.403909455984831 D1 2250.728867440025
3 3 L1 10.536609089933336 D1 2250.617823170711
21 21 L2 9.371508447453380 D2 2600.426524913943
22 22 L2 10.867016064003110 D2 2600.741539767582
23 23 L2 9.151747692376375 D2 2599.127749662441
31 31 L3 10.733573765493929 D3 1805.580214313545
32 32 L3 10.086726178415120 D3 1799.793218221674
33 33 L3 9.055966132320464 D3 1799.712614282717
51 51 L4 8.916218001395464 D4 2099.328088438209
52 52 L4 11.705493338406086 D4 2099.892279971070
53 53 L4 8.345597507432103 D4 2100.291966621568
71 71 L5 11.453125244937837 D5 1997.372059857832
72 72 L5 10.272650724276900 D5 2001.424327782651
73 73 L5 9.875873841345310 D5 1998.545463821464

Indexación de data.frames

La indexación de los data.frames es idéntica al de las matrices; sin embargo, tiene una ventaja adicional, esta ventaja radica en que podemos llamar una columna completa indicando el nombre de esta en vez del número. De este modo en el ejemplo de pollitos, no importa si no sabemos la posición exacta de la columna dieta R la encontrará por nosotros.

Veamos como hacerlo, imprimamos los primeros 10 elementos de la columna dieta

##  [1] "D1" "D1" "D1" "D1" "D1" "D1" "D1" "D1" "D1" "D1"

Otra forma de realizar la operación anterior es utilizando el símbolo de \(\$\)

##  [1] "D1" "D1" "D1" "D1" "D1" "D1" "D1" "D1" "D1" "D1"

Las listas

Es momento de introducir a uno de los objetos estrella de R, este es el objeto lista. Al igual que los vectores, las listas son arreglos unidimensionales con la peculiaridad de que los elementos que las integran pueden ser de varias clases, por ejemplo, data.frames, matrices, vectores, rasters, etc. A continuación veamos cómo crear una lista que contiene como elementos un data.frame, un vector y una lista, esta se crea con el comando list()

## $vector
##  [1] 0.6674384495709091 0.3166079800575972 0.2091691677924246
##  [4] 0.8101034904830158 0.4023213370237499 0.7339396050665528
##  [7] 0.3430559027474374 0.2719428758136928 0.2580246895086020
## [10] 0.2703380563762039
## 
## $pollitos_df
##    pollito_id lote       peso_inicial Dieta        peso_dieta
## 1           1   L1 10.117280656471848    D1 2250.309358306802
## 2           2   L1  8.403909455984831    D1 2250.728867440025
## 3           3   L1 10.536609089933336    D1 2250.617823170711
## 4           4   L1  8.610344759188592    D1 2249.559925064307
## 5           5   L1  9.489903860725462    D1 2249.941686784352
## 6           6   L1  9.085298858582973    D1 2248.515006175336
## 7           7   L1 10.397562945261598    D1 2251.826015478549
## 8           8   L1  9.770166626200080    D1 2250.062495431031
## 9           9   L1  8.384311466477811    D1 2250.066361118338
## 10         10   L1 10.447234948165715    D1 2249.758267978024
## 
## $sublista
## $sublista$a
##  [1]  1  2  3  4  5  6  7  8  9 10

Extracción de los elementos de la lista

Como habíamos visto en la sección anterior, las listas se comportan como vectores y por tanto la forma de extraer un elemento de esta simplemente es ocupando la sintaxis lista[[element_index]].

pollito_id lote peso_inicial Dieta peso_dieta
1 L1 10.117280656471848 D1 2250.309358306802
2 L1 8.403909455984831 D1 2250.728867440025
3 L1 10.536609089933336 D1 2250.617823170711
4 L1 8.610344759188592 D1 2249.559925064307
5 L1 9.489903860725462 D1 2249.941686784352
6 L1 9.085298858582973 D1 2248.515006175336
7 L1 10.397562945261598 D1 2251.826015478549
8 L1 9.770166626200080 D1 2250.062495431031
9 L1 8.384311466477811 D1 2250.066361118338
10 L1 10.447234948165715 D1 2249.758267978024

Otra forma de extraer un elemento de la lista es con la sintaxis lista$nombre_elemento

pollito_id lote peso_inicial Dieta peso_dieta
1 L1 10.117280656471848 D1 2250.309358306802
2 L1 8.403909455984831 D1 2250.728867440025
3 L1 10.536609089933336 D1 2250.617823170711
4 L1 8.610344759188592 D1 2249.559925064307
5 L1 9.489903860725462 D1 2249.941686784352
6 L1 9.085298858582973 D1 2248.515006175336
7 L1 10.397562945261598 D1 2251.826015478549
8 L1 9.770166626200080 D1 2250.062495431031
9 L1 8.384311466477811 D1 2250.066361118338
10 L1 10.447234948165715 D1 2249.758267978024

o bien lista[["nombre_elemento"]]

pollito_id lote peso_inicial Dieta peso_dieta
1 L1 10.117280656471848 D1 2250.309358306802
2 L1 8.403909455984831 D1 2250.728867440025
3 L1 10.536609089933336 D1 2250.617823170711
4 L1 8.610344759188592 D1 2249.559925064307
5 L1 9.489903860725462 D1 2249.941686784352
6 L1 9.085298858582973 D1 2248.515006175336
7 L1 10.397562945261598 D1 2251.826015478549
8 L1 9.770166626200080 D1 2250.062495431031
9 L1 8.384311466477811 D1 2250.066361118338
10 L1 10.447234948165715 D1 2249.758267978024

Extrayendo elementos contenidos en una lista de listas

Estamos interesados en extraer el elemento 10 del vector a contenido en la lista nombrada sublista que se encuentra dentro de nuestra lista principal. La sintaxis para extraer un elemento de una lista contenida dentro de otra lista es lista[[indice_nivel_1]][[indice_nivel_2]][[indice_nivel3]]

## [1] 10

o bien

## [1] 10

Agregando nuevos elementos a una lista

Agreguemos un nuevo elemento (un vector de números aleatorios) a lista

## $vector
##  [1] 0.6674384495709091 0.3166079800575972 0.2091691677924246
##  [4] 0.8101034904830158 0.4023213370237499 0.7339396050665528
##  [7] 0.3430559027474374 0.2719428758136928 0.2580246895086020
## [10] 0.2703380563762039
## 
## $pollitos_df
##    pollito_id lote       peso_inicial Dieta        peso_dieta
## 1           1   L1 10.117280656471848    D1 2250.309358306802
## 2           2   L1  8.403909455984831    D1 2250.728867440025
## 3           3   L1 10.536609089933336    D1 2250.617823170711
## 4           4   L1  8.610344759188592    D1 2249.559925064307
## 5           5   L1  9.489903860725462    D1 2249.941686784352
## 6           6   L1  9.085298858582973    D1 2248.515006175336
## 7           7   L1 10.397562945261598    D1 2251.826015478549
## 8           8   L1  9.770166626200080    D1 2250.062495431031
## 9           9   L1  8.384311466477811    D1 2250.066361118338
## 10         10   L1 10.447234948165715    D1 2249.758267978024
## 
## $sublista
## $sublista$a
##  [1]  1  2  3  4  5  6  7  8  9 10
## 
## 
## $nuevo_elem
##  [1]  0.97309580341957713 -0.49495061263254697 -0.88630769205201243
##  [4]  0.21847577953859154 -0.97136251877093360 -1.53382550318389321
##  [7] -0.87412972245777842 -0.93132674662247461  0.74117594452810953
## [10]  0.36336154516725550  1.13205687874389183 -0.09090987368485527
## [13] -2.04941473397258367 -2.03121280594474118 -0.69984289514123232
## [16] -2.10519402185569682  0.13796115279405854  0.23800869735825450
## [19]  0.59828991158728573  0.09546808567557649 -0.10280564394482722
## [22] -0.06346768393935726  1.25403292281735323  0.46866940123108491
## [25] -0.74785890924919740  0.63571016117349743  0.07026751232511391
## [28] -2.33653669802009878 -0.72547849270724474  0.21115549461532390

o bien

## $vector
##  [1] 0.6674384495709091 0.3166079800575972 0.2091691677924246
##  [4] 0.8101034904830158 0.4023213370237499 0.7339396050665528
##  [7] 0.3430559027474374 0.2719428758136928 0.2580246895086020
## [10] 0.2703380563762039
## 
## $pollitos_df
##    pollito_id lote       peso_inicial Dieta        peso_dieta
## 1           1   L1 10.117280656471848    D1 2250.309358306802
## 2           2   L1  8.403909455984831    D1 2250.728867440025
## 3           3   L1 10.536609089933336    D1 2250.617823170711
## 4           4   L1  8.610344759188592    D1 2249.559925064307
## 5           5   L1  9.489903860725462    D1 2249.941686784352
## 6           6   L1  9.085298858582973    D1 2248.515006175336
## 7           7   L1 10.397562945261598    D1 2251.826015478549
## 8           8   L1  9.770166626200080    D1 2250.062495431031
## 9           9   L1  8.384311466477811    D1 2250.066361118338
## 10         10   L1 10.447234948165715    D1 2249.758267978024
## 
## $sublista
## $sublista$a
##  [1]  1  2  3  4  5  6  7  8  9 10
## 
## 
## $nuevo_elem
##  [1]  0.97309580341957713 -0.49495061263254697 -0.88630769205201243
##  [4]  0.21847577953859154 -0.97136251877093360 -1.53382550318389321
##  [7] -0.87412972245777842 -0.93132674662247461  0.74117594452810953
## [10]  0.36336154516725550  1.13205687874389183 -0.09090987368485527
## [13] -2.04941473397258367 -2.03121280594474118 -0.69984289514123232
## [16] -2.10519402185569682  0.13796115279405854  0.23800869735825450
## [19]  0.59828991158728573  0.09546808567557649 -0.10280564394482722
## [22] -0.06346768393935726  1.25403292281735323  0.46866940123108491
## [25] -0.74785890924919740  0.63571016117349743  0.07026751232511391
## [28] -2.33653669802009878 -0.72547849270724474  0.21115549461532390
## 
## $nuevo_elem_2
##  [1] 0 0 1 1 1 0 0 0 0 0 1 0 0 1 1 1 0 0 0 0 0 0 0 1 0 0 0 1 1 0

Leyendo datos en R

Se pueden importar datos tabulados provenientes de varios formatos. Los más comunes son .csv,.txt y .xls. Los comandos para leer estos formatos son read.csv, read.table, read.xls (en el paquete gdata) y loadWorkbook (en el paquete XLConnect).

En este documento veremos cómo cargar datos con los comandos read.csv y read.table. El primero sirve para leer datos separados por comas y el segundo por tabulaciones.

Algunas bases de datos contienen otro tipo de separadores, tales como “;” “:” o cualquier otro caracter. Tanto read.csv como read.table tienen un argumento que permite indicar el caracter sepador, este argumento es sep = "caracter". Así, si nuestra base de datos estuviera separada por “;”, sólo tendríamos que indicarlo de la siguiente manera: sep=";".

Veamos algunos ejemplos concretos.

  • Datos separados por comas
species long lat
bradypus_variegatus -65.40000000000001 -10.3833
bradypus_variegatus -65.38330000000001 -10.3833
bradypus_variegatus -65.13330000000001 -16.8000
bradypus_variegatus -63.66670000000000 -17.4500
bradypus_variegatus -63.85000000000000 -17.4000
bradypus_variegatus -64.41670000000001 -16.0000
  • Datos separados por tabulaciones
name longitude latitude issues
Ambystoma tigrinum -92.48258000000000 34.46026 cdround,gass84
Ambystoma tigrinum -95.88531999999999 31.93524 cdround,gass84
Ambystoma tigrinum -93.27306000000000 45.21076 cdround,gass84
Ambystoma tigrinum -96.32323000000000 44.00937 cdround,gass84
Ambystoma tigrinum -95.60391000000000 41.46921 cdround,gass84
Ambystoma tigrinum -97.75873000000000 35.26342 cdround,gass84
  • Usando read.csv para leer datos separados por tabulaciones
name longitude latitude issues
Ambystoma tigrinum -92.48258 34.46026 cdround,gass84
Ambystoma tigrinum -95.88532 31.93524 cdround,gass84
Ambystoma tigrinum -93.27306 45.21076 cdround,gass84
Ambystoma tigrinum -96.32323 44.00937 cdround,gass84
Ambystoma tigrinum -95.60391 41.46921 cdround,gass84
Ambystoma tigrinum -97.75873 35.26342 cdround,gass84

Nota: una cuestión que debemos de tomar en cuenta cuando leemos datos en R es la codificación de nuestro sistema, ya que esto puede causar que no podamos leer un archivo. Algunas de las codificaciones más frecuentes son: UTF-8 (default en MAC), ASCII, WINDOWS-1252 y las ISO-xxxx-x. En R podemos especificar la codificación con el argumento fileEncoding de las funciones read.csv y read.table

prov key datasetKey
gbif 1265535984 50c9509d-22c7-4a22-a47d-8c48425ef4a7
gbif 1088947578 50c9509d-22c7-4a22-a47d-8c48425ef4a7
gbif 1088946504 50c9509d-22c7-4a22-a47d-8c48425ef4a7
gbif 1143544830 50c9509d-22c7-4a22-a47d-8c48425ef4a7
gbif 1227733876 50c9509d-22c7-4a22-a47d-8c48425ef4a7
gbif 1252601766 2e64dedd-0996-4cd6-b6cd-4f055a46c38c

Un ejemplo de como leer archivos de Excel

Como se mencionó anteriormente, en R es posible leer archivos de Excel utilizando las funciones read.xls y loadWorkbook de los paquetes gdata y XLConnect respectivamente. Veamos cómo instalar estos paquetes para utilizar las funciones señaladas.

  • Con read.xls sólo tenemos que señalar la ruta donde se encuentra nuestro xls y la hoja del libro.
## gdata: read.xls support for 'XLS' (Excel 97-2004) files ENABLED.
## 
## gdata: read.xls support for 'XLSX' (Excel 2007+) files ENABLED.
## 
## Attaching package: 'gdata'
## The following object is masked from 'package:stats':
## 
##     nobs
## The following object is masked from 'package:utils':
## 
##     object.size
## The following object is masked from 'package:base':
## 
##     startsWith
IterationNo AUC_at_Value_0.95 AUC_at_0.5 AUC_ratio
1 0.6904844465485830 0.455461834131189 1.51600945415264
2 0.6502447312374160 0.440165890604005 1.47727196749648
3 0.7395332992408410 0.466813435453584 1.58421596953881
4 0.6904844465485830 0.455461834131189 1.51600945415264
5 0.7908706395783081 0.479626956033633 1.64892867181312
6 0.6259150694167050 0.433288054415460 1.44457033384203

Veamos cómo hacer lo anterior con el paquete XLConnect

## Loading required package: XLConnectJars
## XLConnect 0.2-15 by Mirai Solutions GmbH [aut],
##   Martin Studer [cre],
##   The Apache Software Foundation [ctb, cph] (Apache POI),
##   Graph Builder [ctb, cph] (Curvesapi Java library)
## http://www.mirai-solutions.com
## https://github.com/miraisolutions/xlconnect
## [1] "ROC"  "OCCS"
IterationNo AUC_at_Value_0.95 AUC_at_0.5 AUC_ratio
1 0.6904844465485830 0.455461834131189 1.51600945415264
2 0.6502447312374160 0.440165890604005 1.47727196749648
3 0.7395332992408410 0.466813435453584 1.58421596953881
4 0.6904844465485830 0.455461834131189 1.51600945415264
5 0.7908706395783081 0.479626956033633 1.64892867181312
6 0.6259150694167050 0.433288054415460 1.44457033384203

Estructuras de Control y Loops

Programar implica escribir instrucciones relativamente complejas y repetir de manera iterada algunas de ellas. Hay dos grandes tipos de programación:

  1. La programación imperativa en donde se le indica a la computadora de manera consecutiva un conjunto de operaciones.

  2. La programación declarativa en donde se da una descripción del resultado final (i.e HTML, \(\LaTeX\)) sin especificar cómo se obtiene tal resultado.

Dentro de cada uno de estos estilos generales hay subdivisiones y algunos programas pueden contener varios aspectos de ellos. De manera específica en R, podemos encontrar a la programación modular (paquetes), la orientada a objetos y funcional.

A continuación veremos unas estructuras conocidas como estructuras de control. Estas controlan cuántas veces una operación debe de repetirse.

La sentencia if

if es una sentencia cuya entrada es una operación de tipo lógica y nos permite probar si alguna condición se cumple o no. El diagrama de flujo para la sentencia if es el siguiente

La sintaxis if en R:

Imaginemos que nos interesa hacer un conjunto de operaciones sólo sobre los números divisibles entre 2 (pares) y descartar aquellos números que no son pares, a continuación veremos cómo utilizar if para lograr nuestro cometido.

## 1 No es par
## 2 Es par
## 3 No es par
## 4 Es par

for loop

Supongamos que saber cuáles son los números que son pares en un vector de 100 elementos; esto implicaría repetir 100 veces el código de la sección anterior. La sentencia for permite especificar con tan solo una pocas líneas de código operaciones que se repiten n veces.

La sintaxis del for loop en R es

##   [1] 271 414 320 467 442 477 217 341 154 312 316 238 167 500 450 169 392
##  [18] 302 358 505 313 207 471 416 180 462 251 199 503 303 535 441 399 364
##  [35] 231 361 317 385 334 398 176 408 166 349 468 512 373 241 461 418 459
##  [52] 291 293 374 330 175 485 276 304 429 314 368 165 437 446 226 491 424
##  [69] 339 242 472 185 223 247 523 209 539 275 228 516 287 240 415 456 367
##  [86] 409 533 474 348 377 363 402 473 375 520 332 225 498 210 159
## 271 No es par
## 414 Es par
## 320 Es par
## 467 No es par
## 442 Es par
## 477 No es par
## 217 No es par
## 341 No es par
## 154 Es par
## 312 Es par
## 316 Es par
## 238 Es par
## 167 No es par
## 500 Es par
## 450 Es par
## 169 No es par
## 392 Es par
## 302 Es par
## 358 Es par
## 505 No es par
## 313 No es par
## 207 No es par
## 471 No es par
## 416 Es par
## 180 Es par
## 462 Es par
## 251 No es par
## 199 No es par
## 503 No es par
## 303 No es par
## 535 No es par
## 441 No es par
## 399 No es par
## 364 Es par
## 231 No es par
## 361 No es par
## 317 No es par
## 385 No es par
## 334 Es par
## 398 Es par
## 176 Es par
## 408 Es par
## 166 Es par
## 349 No es par
## 468 Es par
## 512 Es par
## 373 No es par
## 241 No es par
## 461 No es par
## 418 Es par
## 459 No es par
## 291 No es par
## 293 No es par
## 374 Es par
## 330 Es par
## 175 No es par
## 485 No es par
## 276 Es par
## 304 Es par
## 429 No es par
## 314 Es par
## 368 Es par
## 165 No es par
## 437 No es par
## 446 Es par
## 226 Es par
## 491 No es par
## 424 Es par
## 339 No es par
## 242 Es par
## 472 Es par
## 185 No es par
## 223 No es par
## 247 No es par
## 523 No es par
## 209 No es par
## 539 No es par
## 275 No es par
## 228 Es par
## 516 Es par
## 287 No es par
## 240 Es par
## 415 No es par
## 456 Es par
## 367 No es par
## 409 No es par
## 533 No es par
## 474 Es par
## 348 Es par
## 377 No es par
## 363 No es par
## 402 Es par
## 473 No es par
## 375 No es par
## 520 Es par
## 332 Es par
## 225 No es par
## 498 Es par
## 210 Es par
## 159 No es par

Alternativamente

Ejemplos un poco más laboriosos

Supongan que ahora se les pide guardar en un vector los números que son pares y los que no lo son en otro (para números enteros son los impares).La idea para solucionar nuestro problema es simple, apliquemos el algoritmo par o impar y vayamos guardando (“rellenando”) los resultados en un vector nulo (vacío).

En el vector vec_pares se generaron de manera automática NAs (Not Aviable) cuando la condición es par no se cumplió (R lo hace de manera automática). Lo mismo ocurrió para el vector vec_impares cuando la otra condición no se cumplió (condición es impar).

Veamos cómo quitar los NAs.

##  [1] 414 320 442 154 312 316 238 500 450 392 302 358 416 180 462 364 334
## [18] 398 176 408 166 468 512 418 374 330 276 304 314 368 446 226 424 242
## [35] 472 228 516 240 456 474 348 402 520 332 498 210
##  [1] 271 467 477 217 341 167 169 505 313 207 471 251 199 503 303 535 441
## [18] 399 231 361 317 385 349 373 241 461 459 291 293 175 485 429 165 437
## [35] 491 339 185 223 247 523 209 539 275 287 415 367 409 533 377 363 473
## [52] 375 225 159

De forma similar podemos filtrar los datos con el comando is.na. Debido a que estamos interesados en los datos que no son NA usamos el comando de negación ! para preguntar cuáles no son NA. Finalmente, con el comando which podemos saber las posiciones del vector vec_pares que no son NA.

Si nos preguntáramos de nuestro vector original (vec_num) cuantos son pares y cuantos son impares…

## El numero de enteros pares en vec_num fue de 46
## El numero de enteros impares en vec_num fue de 54

while loop

Habrá situaciones donde no sabemos cuántas iteraciones exactas necesitamos para llegar a cierto resultado. Será necesario hacer los cálculos y evaluar el resultado en cada iteración hasta que la condición que buscamos se cumpla. En esta situaciones podemos ocupar el ciclo while.

Supongamos que se nos pide calcular cuál es el número de la sucesión de Fibonacci más cercano al 400. El algoritmo para encontrar el \(n-esimo\) término de la sucesión de Fibonacci es el siguiente

\[ f_{n} = f_{n-1} + f_{n-2}\,\,\text{para } n=2,3,4,5,...\] Se definen los primeros 2 números como \(f_0=0\) y \(f_1=1\). Se definen los primeros 2 números como \(f_0=0\) y \(f_1=1\). Por tanto \(f_2, f_3,f_4, f_5\,\, y \,\,f_6\) son

\[f_{2}=f_{1}+f_{0}=1+0=1\\f_3=f_2+f_1=1+1=2\\f_4=f_3+f_2=2+1=3\\f_5=f_4+f_3=3+2=5\\f_6=f_5+f_4=5+3=8\]

Ahora vemos cómo generar la secuencia de números de Fibonacci menores a 400 usando while.

##  [1]   0   1   1   2   3   5   8  13  21  34  55  89 144 233 377

¿Cuál es la posición del elemento de la sucesión más cercano a 400?

## [1] 15

Funciones definidas por el usuario.

Es común que hagamos ciertas operaciones de manera repetida y como consecuencia de ello tengamos que duplicar código que ya hemos ocupado con anterioridad. Lo anterior hace nuestros programas o scripts sean enormes y con mucha información redundante. Las funciones definidas por el usuarios precisamente están pensadas para que cuando tengamos que hacer una operación de manera repetida podamos llamar código con una sola instrucción sin tener que escribir todo nuevamente.

En R podemos definir nuestras propias funciones de manera fácil. Veremos cómo definir una función para preguntar si un número entero es par o impar. Asimismo, definiremos una función para generar los primeros \(n\) números de la secuencia de Fibonacci.

La operaciones vectorizadas

Dentro de las críticas más fuertes que se le hacen a R es que es un lenguaje “lento”. Una de las razones de ello, es que al ser un leguaje interpretado, R pregunta el tipo de variable (integer, floating, char, etc) en el tiempo de ejecución, sus instrucciones se traducen o interpretan una a una, cada vez que se ejecuta el programa. Cuando asignamos un valor a una variable, digamos a <- 1.0 lo que hace el interprete de R es preguntar:

  • Ese número 1.0 es de tipo flotante
  • La variable a es de tipo numérica
  • Poner un lugar en la memoria donde almacenar el 1.0
  • Registar “a” como un puntero a ese lugar de memoria.

Para una explicación maravillosa sobre este tópico ver el artículo de Noam Ross

En los leguajes compilados (C, C++, fortran) declaramos los tipos de las variables desde un principio, sus instrucciones se traducen a código máquina de manera directa y optimizada mediante un compilador, lo que los hace más eficientes.

En R una forma de abordar el problema de eficiencia es utilizando operaciones vectorizadas siempre que sea posible. Las operaciones vectorizadas permiten a R llamar funciones de alto nivel que ejecutan código de C, lo que resulta en programas mucho más rápidos.

Comparemos el rendimiento de operaciones no vectorizadas vs. vectorizadas.

Operaciones no vectorizadas vs. vectorizadas.

Sea df_occs una base de datos con puntos de presencia de varias especies de reptiles y anfibios; suponga que se le pide filtrar los datos de presencia por especie y construir una lista donde cada elemento de ella es un data.frame que contiene los datos de cada especie. Veremos cómo hacer este filtrado utilizando operaciones no vectorizadas y vectorizadas. Haremos uso de la función system.time para medir el tiempo que tarde en correr los algoritmos…

Primero leemos la base de datos de los puntos de presencia y exploramos la base de datos (BD).

## [1] 4000    6
name longitude latitude prov date key
Sceloporus occidentalis -120.65935 37.8203800000000 gbif 2016-03-16 1262381503
Pseudacris regilla -121.98533 40.4388299990685 gbif 2003-06-25 543583266
Gehyra variegata 137.40600 -20.9770000000000 gbif 2009-04-12 1085956160
Lampropholis delicata 150.59459 -34.5286200331773 gbif 2012-04-01 1074452855
Zootoca vivipara 10.36416 59.9032500000000 gbif 2015-07-31 1238773985
Chamaeleo dilepis 29.45000 -23.8166700000000 gbif 1916-11-19 287041669
## [1] "name"      "longitude" "latitude"  "prov"      "date"      "key"
##   [1] Sceloporus occidentalis      Pseudacris regilla          
##   [3] Gehyra variegata             Lampropholis delicata       
##   [5] Zootoca vivipara             Chamaeleo dilepis           
##   [7] Rana pretiosa                Ctenotus taeniolatus        
##   [9] Egernia cunninghami          Anolis lemurinus            
##  [11] Psammodromus algirus         Craugastor fleischmanni     
##  [13] Anaxyrus debilis             Eremiascincus richardsonii  
##  [15] Tiliqua rugosa               Eurycea bislineata          
##  [17] Dipsosaurus dorsalis         Liolaemus bibronii          
##  [19] Desmognathus fuscus          Notechis scutatus           
##  [21] Austrelaps superbus          Egernia saxatilis           
##  [23] Anolis carolinensis          Sphaerodactylus nicholsi    
##  [25] Rana cascadae                Egernia striolata           
##  [27] Sceloporus undulatus         Sceloporus variabilis       
##  [29] Stellagama stellio           Lepidophyma flavimaculatum  
##  [31] Lacerta agilis               Bassiana duperreyi          
##  [33] Varanus varius               Pseudacris cadaverina       
##  [35] Ctenotus regius              Lithobates pipiens          
##  [37] Sceloporus graciosus         Amphibolurus muricatus      
##  [39] Xantusia vigilis             Incilius alvarius           
##  [41] Heteronotia binoei           Anaxyrus cognatus           
##  [43] Eleutherodactylus coqui      Takydromus sexlineatus      
##  [45] Uta stansburiana             Psammodromus hispanicus     
##  [47] Rhinella marina              Incilius marmoreus          
##  [49] Incilius mazatlanensis       Hemiergis decresiensis      
##  [51] Moloch horridus              Pseudonaja textilis         
##  [53] Plestiodon gilberti          Ctenotus uber               
##  [55] Liolaemus darwinii           Sphaerodactylus macrolepis  
##  [57] Lithobates warszewitschii    Platysaurus intermedius     
##  [59] Liolaemus koslowskyi         Tiliqua nigrolutea          
##  [61] Anolis humilis               Sceloporus malachiticus     
##  [63] Eremiascincus fasciolatus    Liolaemus kingii            
##  [65] Hemiergis peronii            Liolaemus quilmes           
##  [67] Pachymedusa dacnicolor       Lithobates palmipes         
##  [69] Sceloporus merriami          Dendrobates auratus         
##  [71] Anolis intermedius           Liopholis inornata          
##  [73] Parasuta flagellum           Liolaemus boulengeri        
##  [75] Anolis gundlachi             Podarcis muralis            
##  [77] Liolaemus robustus           Smilisca fodiens            
##  [79] Liolaemus tenuis             Liolaemus rothi             
##  [81] Liolaemus kriegi             Pseudemoia entrecasteauxii  
##  [83] Pseudemoia spenceri          Protobothrops mucrosquamatus
##  [85] Liolaemus fitzingerii        Lobulia elegans             
##  [87] Liolaemus pictus             Eulamprus kosciuskoi        
##  [89] Anolis cupreus               Liolaemus elongatus         
##  [91] Anolis cristatellus          Anaxyrus canorus            
##  [93] Tarentola boettgeri          Anolis lionotus             
##  [95] Takydromus septentrionalis   Hyla walkeri                
##  [97] Anolis tropidolepis          Liolaemus petrophilus       
##  [99] Anolis cooki                 Sphaerodactylus klauberi    
## [101] Liolaemus chacoensis         Liolaemus multimaculatus    
## [103] Phymaturus patagonicus       Liolaemus scapularis        
## [105] Liolaemus melanops           Liolaemus olongasta         
## [107] Liolaemus tari               Liolaemus walkeri           
## [109] Rankinia diemensis          
## 109 Levels: Amphibolurus muricatus Anaxyrus canorus ... Zootoca vivipara

Algoritmo de búsqueda no vectorizado

Primero definimos la lista en donde guardaremos los data.frames de cada especie. Nótese que la lista tendrá tantos elementos como especies en la BD.

Ahora implementamos el algoritmo de búsqueda. La idea básica es ir recorriendo toda la columana name de la base de datos occs_bd e ir preguntando cuál registro cumple la condición occs_bd$name == sp_name_i; posteriormente almacenar estos índices en un vector llamado sp_index con los índices que cumplen la condición. Finalmente hacer un subset de occs_bd con sp_index.

##                        name  longitude latitude prov       date        key
## 1   Sceloporus occidentalis -120.65935 37.82038 gbif 2016-03-16 1262381503
## 82  Sceloporus occidentalis -121.14692 38.74038 gbif 2016-02-29 1253314410
## 207 Sceloporus occidentalis -122.51346 37.58788 gbif 2016-01-09 1229611922
## 322 Sceloporus occidentalis -121.77272 36.24722 gbif 2016-03-13 1265555690
## 353 Sceloporus occidentalis -121.08638 36.59649 gbif 2016-03-20 1262386382
## 422 Sceloporus occidentalis -122.35500 38.42160 gbif 2016-03-27 1265574213
## [1] 56  6

Cuánto tardó en correr?

##                user              system             elapsed 
## 18.6540000000000035  0.1719999999999999 23.0140000000000029

Algoritmo de búsqueda vectorizado

Utilizaremos un comando de mi lista de estrellas, este es which

Combinamos la operación vectorizada which con el ciclo for

## [1] 56  6

Cuánto tardo con el vectorizado??

##                user              system             elapsed 
## 0.01700000000000301 0.00000000000000000 0.01700000000000301

Cuántas veces corrió más rápido el código vectorizado?

## [1] 1353.764705882113

La familia apply

La familia de funciones apply tienen como objetivo operar sobre estructuras de datos como matrix, data.frames, arrays, y lists de forma repetitiva. Estas funciones aplican una función sobre un conjunto de datos y devuelven un arreglo el cual puede ser una matriz, una tabla de datos o una lista. Una característica de ellas, es que permiten evitar los loops, por lo que serán necesarias menos líneas de código para llegar a un mismo resultado (el código suele ser más elegante).

Entre los R-programadores se suele decir que es más R-tónico (en alusión a pythonico) utilizar las funciones de la familia apply sobre los loops.

Veamos cuales funciones conforman esta familia y sus ouputs (es información la tomé de esta página):

Función
base::apply Apply Functions Over Array Margins
base::by Apply a Function to a Data Frame Split by Factors
base::eapply Apply a Function Over Values in an Environment
base::lapply Apply a Function over a List or Vector
base::mapply Apply a Function to Multiple List or Vector Arguments
base::rapply Recursively Apply a Function to a List
base::tapply Apply a Function Over a Ragged Array

lapply

La función lappy regresa una lista cuyos elementos pueden ser cualquier tipo de estructura de datos (matrix, data.frames, arrays, lists, etc.).

Veremos cómo implementar nuestro algortimo de búsqueda y filtrado de datos por especie utilizando las apply functions.

Como se había mencionado anteriormente las funciones de esta gran familia aplican una función (generalmente definida por el usuario) sobre una estructura de datos y por lo tanto, para implementar nuestro algoritmo de búsqueda será necesario definir nuestra función.

Apliquemos nuestra función usando la sintaxis lapply. En esta sólo hay que especificar un vector de índices o listas (X) sobre el cual la función que definimos va a operar (find_sp).

Usando una función que llama a c

Comparemos los rendimientos de nuestras implementaciones:

## Tiempo de ejecucion: 23.014 algoritmo no vectorizado
## Tiempo de ejecucion: 0.01700000000000301 algoritmo vectorizado
## Tiempo de ejecucion: 0.03600000000000136 algoritmo vectorizado y lappy
## Tiempo de ejecucion: 0.01100000000000279 split

purrr programación funcional

La idea es mapear una los elementos de una lista y aplicar una función. Calculemos el polígono convexo de los puntos de presencia de las especies

  • Primero creamos la función para estimar los puntos que formaran el polígono convexo.
  • Convertimos en una lista el data.frame de la base de datos de presencia

Graficaremos los polígonos convexos de 5 especies tomadas al azar

## $`Lepidophyma flavimaculatum`
## NULL
## 
## $`Pachymedusa dacnicolor`
## NULL
## 
## $`Eremiascincus richardsonii`
## NULL
## 
## $`Tiliqua rugosa`
## NULL
## 
## $`Smilisca fodiens`
## NULL

Paquetes usados durante este tutorial

## R version 3.5.1 (2018-07-02)
## Platform: x86_64-apple-darwin15.6.0 (64-bit)
## Running under: macOS High Sierra 10.13.6
## 
## Matrix products: default
## BLAS: /Library/Frameworks/R.framework/Versions/3.5/Resources/lib/libRblas.0.dylib
## LAPACK: /Library/Frameworks/R.framework/Versions/3.5/Resources/lib/libRlapack.dylib
## 
## locale:
## [1] en_US.UTF-8/en_US.UTF-8/en_US.UTF-8/C/en_US.UTF-8/en_US.UTF-8
## 
## attached base packages:
## [1] stats     graphics  grDevices utils     datasets  methods   base     
## 
## other attached packages:
## [1] XLConnect_0.2-15     XLConnectJars_0.2-15 gdata_2.18.0        
## [4] knitr_1.21           dygraphs_1.1.1.6    
## 
## loaded via a namespace (and not attached):
##  [1] Rcpp_1.0.0       compiler_3.5.1   later_0.7.5      questionr_0.7.0 
##  [5] highr_0.7        rmdformats_0.3.3 tools_3.5.1      xts_0.10-2      
##  [9] digest_0.6.18    jsonlite_1.6     evaluate_0.12    lattice_0.20-35 
## [13] rlang_0.3.1      shiny_1.2.0      rstudioapi_0.7   yaml_2.2.0      
## [17] xfun_0.4         rJava_0.9-10     stringr_1.3.1    htmlwidgets_1.2 
## [21] gtools_3.8.1     grid_3.5.1       R6_2.3.0         rmarkdown_1.11  
## [25] bookdown_0.7     purrr_0.2.5      magrittr_1.5     promises_1.0.1  
## [29] htmltools_0.3.6  mime_0.6         xtable_1.8-3     httpuv_1.4.5    
## [33] stringi_1.2.4    miniUI_0.1.1.1   zoo_1.8-3

Luis Osorio Olvera ()

2019-01-26